<?php
declare(strict_types=1);

namespace SixShop\MakerBundle\Generator;

use Symfony\Component\Console\Style\SymfonyStyle;

class ControllerGenerator
{
    private string $templatesPath;

    public function __construct()
    {
        $this->templatesPath = __DIR__ . '/../../templates';
    }

    /**
     * Generate API and Admin controllers
     */
    public function generateControllers(
        string $tableName, 
        string $tableComment, 
        array $fields, 
        array $extensionInfo, 
        string $targetPath, 
        SymfonyStyle $io
    ): bool {
        try {
            $success = true;
            
            // Generate API Controller
            $success = $this->generateApiController($tableName, $tableComment, $fields, $extensionInfo, $targetPath, $io) && $success;
            
            // Generate Admin Controller
            $success = $this->generateAdminController($tableName, $tableComment, $fields, $extensionInfo, $targetPath, $io) && $success;
            
            return $success;
            
        } catch (\Exception $e) {
            $io->error('生成控制器时发生错误: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Generate API controller
     */
    private function generateApiController(
        string $tableName, 
        string $tableComment, 
        array $fields, 
        array $extensionInfo, 
        string $targetPath, 
        SymfonyStyle $io
    ): bool {
        try {
            $controllerName = $this->generateControllerName($tableName);
            $controllerPath = $targetPath . '/src/Controller/Api';
            
            // Ensure controller directory exists
            if (!is_dir($controllerPath)) {
                if (!mkdir($controllerPath, 0755, true)) {
                    $io->error("无法创建API控制器目录: {$controllerPath}");
                    return false;
                }
            }
            
            $fileName = $controllerName . '.php';
            $filePath = $controllerPath . '/' . $fileName;
            
            // Check if file exists
            if (file_exists($filePath)) {
                if (!$io->confirm("API控制器文件已存在: {$fileName}，是否覆盖?", false)) {
                    $io->text("跳过API控制器文件: {$fileName}");
                    return true;
                }
            }
            
            // Prepare template variables
            $templateVars = $this->prepareTemplateVariables($tableName, $tableComment, $fields, $extensionInfo, 'Api');
            
            // Generate content using template
            ob_start();
            extract($templateVars);
            include $this->templatesPath . '/src/Controller/Api/Controller.php.tpl.php';
            $content = ob_get_clean();
            
            // Write file
            if (file_put_contents($filePath, $content) !== false) {
                $io->text("✓ 生成API控制器: src/Controller/Api/{$fileName}");
                return true;
            } else {
                $io->error("✗ 无法写入API控制器文件: {$fileName}");
                return false;
            }
            
        } catch (\Exception $e) {
            $io->error('生成API控制器时发生错误: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Generate Admin controller
     */
    private function generateAdminController(
        string $tableName, 
        string $tableComment, 
        array $fields, 
        array $extensionInfo, 
        string $targetPath, 
        SymfonyStyle $io
    ): bool {
        try {
            $controllerName = $this->generateControllerName($tableName);
            $controllerPath = $targetPath . '/src/Controller/Admin';
            
            // Ensure controller directory exists
            if (!is_dir($controllerPath)) {
                if (!mkdir($controllerPath, 0755, true)) {
                    $io->error("无法创建Admin控制器目录: {$controllerPath}");
                    return false;
                }
            }
            
            $fileName = $controllerName . '.php';
            $filePath = $controllerPath . '/' . $fileName;
            
            // Check if file exists
            if (file_exists($filePath)) {
                if (!$io->confirm("Admin控制器文件已存在: {$fileName}，是否覆盖?", false)) {
                    $io->text("跳过Admin控制器文件: {$fileName}");
                    return true;
                }
            }
            
            // Prepare template variables
            $templateVars = $this->prepareTemplateVariables($tableName, $tableComment, $fields, $extensionInfo, 'Admin');
            
            // Generate content using template
            ob_start();
            extract($templateVars);
            include $this->templatesPath . '/src/Controller/Admin/Controller.php.tpl.php';
            $content = ob_get_clean();
            
            // Write file
            if (file_put_contents($filePath, $content) !== false) {
                $io->text("✓ 生成Admin控制器: src/Controller/Admin/{$fileName}");
                return true;
            } else {
                $io->error("✗ 无法写入Admin控制器文件: {$fileName}");
                return false;
            }
            
        } catch (\Exception $e) {
            $io->error('生成Admin控制器时发生错误: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Prepare template variables
     */
    private function prepareTemplateVariables(
        string $tableName, 
        string $tableComment, 
        array $fields, 
        array $extensionInfo, 
        string $type
    ): array {
        $controllerName = $this->generateControllerName($tableName);
        $modelName = $this->generateModelName($tableName);
        $entityName = $this->generateEntityName($tableName);
        $namespace = rtrim($extensionInfo['namespace'], '\\') . '\\';
        
        // Get searchable fields (string fields that are not too long)
        $searchableFields = $this->getSearchableFields($fields);
        
        return [
            'tableName' => $tableName,
            'tableComment' => $tableComment,
            'controllerName' => $controllerName,
            'modelName' => $modelName,
            'entityName' => $entityName,
            'namespace' => $namespace,
            'fields' => $fields,
            'searchableFields' => $searchableFields,
            'type' => $type
        ];
    }

    /**
     * Generate controller class name from table name
     */
    private function generateControllerName(string $tableName): string
    {
        $baseName = $this->generateBaseName($tableName);
        return $baseName . 'Controller';
    }
    
    /**
     * Generate base class name from table name
     */
    private function generateBaseName(string $tableName): string
    {
        // Remove common prefixes
        $tableName = preg_replace('/^(tbl_|tb_|t_)/', '', $tableName);
        
        // Convert to PascalCase and make singular
        $parts = explode('_', $tableName);
        $parts = array_map('ucfirst', $parts);
        $name = implode('', $parts);
        
        // Make singular (simple rules)
        if (str_ends_with($name, 's') && !str_ends_with($name, 'ss')) {
            $name = substr($name, 0, -1);
        }
        
        return $name;
    }

    /**
     * Generate model class name from table name
     */
    private function generateModelName(string $tableName): string
    {
        $baseName = $this->generateBaseName($tableName);
        return $baseName . 'Model';
    }

    /**
     * Generate entity class name from table name
     */
    private function generateEntityName(string $tableName): string
    {
        $baseName = $this->generateBaseName($tableName);
        return $baseName . 'Entity';
    }

    /**
     * Get searchable fields for the controllers
     */
    private function getSearchableFields(array $fields): array
    {
        $searchable = [];
        $excludeFields = ['id', 'create_time', 'update_time', 'delete_time'];
        
        foreach ($fields as $field) {
            if (in_array($field['name'], $excludeFields)) {
                continue;
            }
            
            // Include string fields with reasonable length and some other types
            if (($field['type'] === 'string' && (!isset($field['length']) || $field['length'] <= 255)) ||
                in_array($field['type'], ['integer', 'biginteger', 'boolean'])) {
                $searchable[] = $field;
            }
        }
        
        return $searchable;
    }
}